package edu.uts.reekie.designer.implementation.edit;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import org.eclipse.draw2d.ChopboxAnchor;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.EllipseAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.AccessibleAnchorProvider;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartListener;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.DropRequest;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.graphics.Image;

import edu.uts.reekie.designer.Messages;
import edu.uts.reekie.designer.implementation.figures.*;
import edu.uts.reekie.designer.implementation.model.*;
import edu.uts.reekie.designer.edit.*;
import edu.uts.reekie.designer.figures.FigureFactory;
import edu.uts.reekie.designer.figures.MultipleFigure;
import edu.uts.reekie.designer.model.ModelFactory;
import edu.uts.reekie.designer.model.Multiple;


public abstract class ViewComponentEditPart extends ViewNodeEditPart {


	public ViewComponentEditPart(ModelFactory mf, FigureFactory ff) {
		super(mf, ff);
	}
	

	protected AccessibleEditPart createAccessible() {
		return new AccessibleGraphicalEditPart(){

			public void getName(AccessibleEvent e) {
				e.result = Messages.LogicPlugin_Tool_CreationTool_LED_Label;
			}
			
			public void getValue(AccessibleControlEvent e) {
				e.result = "dummy value"; // TODO: implement properly
			}

		};
	}

	protected void createEditPolicies(){
		super.createEditPolicies();
		
		installEditPolicy(EditPolicy.COMPONENT_ROLE, new ViewComponentEditPolicy());
		installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new NamedDirectEditPolicy());
		
	}
	
	public void performRequest(Request request){
		if (request.getType() == RequestConstants.REQ_DIRECT_EDIT)
			performDirectEdit();
	}
	
	private void performDirectEdit(){
		Object fs = getFigure();
		
		new NameEditManager(this,
				new NameCellEditorLocator((Figure)getFigure())).show();
	}

	protected abstract IFigure createFigure();
	
	/**
	 * Returns a newly created Figure to represent this.
	 *
	 * @return  Figure of this.
	 
	protected IFigure createFigure() {
		
		ViewComponent model = getViewComponentModel();	
		ViewComponentFigure figure = new ViewComponentFigure();
		figure.setName(model.getName());
		
		figure.setPersistence(model.isService());
		figure.setRealTime(model.isActive());
		figure.setPresentation(model.isUserInitiated());
		
		return figure;
	}
*/

	public Object getAdapter(Class key) {
		if (key == AccessibleAnchorProvider.class)
			return new DefaultAccessibleAnchorProvider() { 
				public List getSourceAnchorLocations() {
					List list = new ArrayList();
					/*
					Vector sourceAnchors = getNodeFigure().getSourceConnectionAnchors();
					for (int i=0; i<sourceAnchors.size(); i++) {
						ConnectionAnchor anchor = (ConnectionAnchor)sourceAnchors.get(i);
						list.add(anchor.getReferencePoint().getTranslated(0, -3));
					}
					*/
					return list;
				}
				public List getTargetAnchorLocations() {
					List list = new ArrayList();
					/*
					Vector targetAnchors = getNodeFigure().getTargetConnectionAnchors();
					for (int i=0; i<targetAnchors.size(); i++) {
						ConnectionAnchor anchor = (ConnectionAnchor)targetAnchors.get(i);
						list.add(anchor.getReferencePoint().getTranslated(0, 3));
					}
					*/
					return list;
				}
			};
		return super.getAdapter(key);
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelSourceConnections()
	 */
	protected List getModelSourceConnections() {
		return getViewComponentModel().getSourceConnections();
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelTargetConnections()
	 */
	protected List getModelTargetConnections() {
		return getViewComponentModel().getTargetConnections();
	}

	/**
	 * Returns the Figure of this ConceptualView Component
	 *
	 * @return  ViewComponentFigure instance
	 */
	public ViewComponentFigure getViewComponentFigure() {
		return (ViewComponentFigure)getFigure();
	}

	/**
	 * Returns the model of this as a conceptual view component.
	 *
	 * @return  Model of this as conceptual view component.
	 */
	protected ViewComponent getViewComponentModel() {
		return (ViewComponent)getModel();
	}

	public void propertyChange(java.beans.PropertyChangeEvent change){
		
		boolean doRefresh = false;
		
		if (change.getPropertyName().equals(ViewComponent.PROPERTY_NAME)) {
			updateName();
			doRefresh = true;
		}	else if (change.getPropertyName().equals(ViewComponent.PROPERTY_CONNECTORS_SOURCE)) {
			refreshSourceConnections();
		} else if (change.getPropertyName().equals(ViewComponent.PROPERTY_CONNECTORS_TARGET)) {
			refreshTargetConnections();
		} else if (change.getPropertyName().equals(ViewComponent.PROPERTY_MULTIPLICITY)) {
			if (supportsMultiple==true){
				updateMultiplicity();
				doRefresh = true;
			}
		}
		
		
		

		if (doRefresh)
			refreshVisuals();
		else 
			super.propertyChange(change);
	}
	
	private void updateMultiplicity() {
		ViewComponentFigure figure = getFigureAs();
		ViewComponent model = getModelAs();
		
		if (figure instanceof MultipleFigure && model instanceof Multiple){
			MultipleFigure mf = (MultipleFigure)figure;
						
			if (mf.isMultiple()!=model.isMultiple()){
				mf.setMultiple(model.isMultiple());
			}
		
			
		}
		
		
	}
	
	private void updateName() {
		((ViewComponentFigure)getFigure()).setName(getViewComponentModel().getName());
	}
	

	
	
	/**
	 * Apart from the usual visual update, it also
	 * updates the name
	 */
	public void refreshVisuals() {
		Rectangle bounds = new Rectangle(getViewComponentModel().getLocation(),
				getViewComponentModel().getSize());
		((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
		super.refreshVisuals();
	}

	public void setSelected(int i){
		super.setSelected(i);
		refreshVisuals();
	}

	
	protected ConnectionAnchor getConnectionAnchor() {
		return new ChopboxAnchor(getViewComponentFigure().getAnchorFigure());
	}
	
	/**
	 * Returns the connection anchor for the given
	 * ConnectorEditPart's source. 
	 *
	 * @return  ConnectionAnchor.
	 */
	public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connEditPart) {
		return getConnectionAnchor();
	}

	/**
	 * Returns the connection anchor of a source connection which
	 * is at the given point.
	 * 
	 * @return  ConnectionAnchor.
	 */
	public ConnectionAnchor getSourceConnectionAnchor(Request request) {
		return getConnectionAnchor();
	}

	/**
	 * Returns the connection anchor for the given 
	 * ConnectorEditPart's target.
	 *
	 * @return  ConnectionAnchor.
	 */
	public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connEditPart) {
		return getConnectionAnchor();
	}

	/**
	 * Returns the connection anchor of a target connection which
	 * is at the given point.
	 *
	 * @return  ConnectionAnchor.
	 */
	public ConnectionAnchor getTargetConnectionAnchor(Request request) {
		return getConnectionAnchor();
	}
	
	boolean supportsMultiple;
	public boolean supportsMultiple() {
		return supportsMultiple;
	}
	
	public void setSupportsMultiple(boolean value){
		supportsMultiple = value;
	}
	
}
